package com.idlestar.androiddocs.net;

import com.alibaba.fastjson.JSONObject;
import com.android.volley.toolbox.StringRequest;
import com.idlestar.androiddocs.common.MyApp;

import java.util.HashMap;

/**
 * 网络请求抽象基类
 */
public abstract class AbsFetch<T> {
    /**
     * 数据获取操作的回调
     */
    protected FetchListener<T> mListener;
    /**
     * 对数据请求进行标记的tag，详情：{@link #AbsFetch(String urlSuffixTag)}
     */
    protected String mUrlSuffixTag;
    /**
     * 是否正在执行数据请求？
     */
    protected boolean isFetching = false;

    /**
     * 构造函数
     * @param urlSuffixTag 用于生成数据请求的唯一标记的的tag，标记字符串将连接在请求数据的url{@link #getRequestUrl()}后，
     *                     最终形成“url + tag”这样的字符串作为请求的标识。
     */
    public AbsFetch(String urlSuffixTag) {
        mUrlSuffixTag = urlSuffixTag;
    }

    /**
     * 设置数据获取操作的回调对象
     * @param listener 监听器
     */
    public void setFetchListener(FetchListener<T> listener) {
        mListener = listener;
    }

    /**
     * 执行数据获取操作
     */
    public void execute() {
        requestData();
    }

    /**
     * 请求数据的回调监听
     * @param <T> 请求的结果数据的类型
     */
    public interface FetchListener<T> {
        void success(T data);
        void error(int errorCode, String errorMsg);
    }

    /**
     * 请求数据
     */
    private void requestData() {
        if (!isFetching) {
            isFetching = true;
            HashMap<String, String> paramsMap = new HashMap<String, String>();
            setParams(paramsMap);
            final String url = getRequestUrl();
            StringRequest stringRequest = NetClient.newPostStringRequest(url,
                    paramsMap, new NetClient.RequestListener<JSONObject>() {

                        @Override
                        public void onEnd() {
                            isFetching = false;
                            NetClient.instance().cancelPendingRequests(url + mUrlSuffixTag);
                        }

                        @Override
                        public void onSuccess(int responseCode, JSONObject jsonObject) {
                            switch (responseCode) {
                                case ResponseCode.SUCCESS:
                                    OperationRunnable runnable =  new OperationRunnable();
                                    runnable.jsonObject = jsonObject;
                                    new Thread(runnable).start();
                                    break;
                                default:
                                    if (mListener != null) {
                                        String error = "";
                                        if (jsonObject.containsKey(ResponseCode.ERROR_MSG_KEY)) {
                                            error = jsonObject.getString(ResponseCode.ERROR_MSG_KEY);
                                        }
                                        mListener.error(responseCode, error);
                                    }
                                    break;
                            }
                        }

                        @Override
                        public void onError(int errorCode, String errorString) {
                            if (mListener != null) {
                                mListener.error(errorCode, errorString);
                            }
                        }
                    });
            NetClient.instance().addToRequestQueue(stringRequest, url + mUrlSuffixTag);
        }
    }

    /**
     * 解析数据的操作使用新线程执行。
     */
    private final class OperationRunnable implements Runnable {
        private JSONObject jsonObject;

        @Override
        public void run() {
            final T data;
            if (jsonObject != null) {
                data = parseJSONObject(jsonObject);
                jsonObject = null;
            } else {
                data = null;
            }

            if (mListener != null) {
                MyApp.instance().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mListener.success(data);
                    }
                }, 0);
            }
        }
    }

    /**
     * 设置请求数据需要的参数
     * @param paramsMap 要添加参数的map对象
     */
    protected void setParams(HashMap<String, String> paramsMap) {}

    /**
     * 对请求的结果数据进行解析
     * @param jsonObject 请求得到的json
     * @return 解析后的结果数据
     */
    protected abstract T parseJSONObject(JSONObject jsonObject);

    /**
     * 获得用于数据请求的url
     * @return url
     */
    protected abstract String getRequestUrl();
}
